package com.bgyrobot.coordinate;

import java.util.HashMap;
import java.util.Map;
import org.locationtech.proj4j.CoordinateReferenceSystem;
import org.locationtech.proj4j.CoordinateTransform;

import com.bgyrobot.coordinate.model.ReferencePoint;
import com.bgyrobot.coordinate.util.GeographyUtil;

/**
 * 纯地理转换，可缓存耗时计算
 * @author hesu
 */
public class Geotransform {
    
    private Map<String, CoordinateReferenceSystem> csPool;
    private Map<String, CoordinateTransform> transformPool;
    
    public Geotransform() {
        csPool = new HashMap<String, CoordinateReferenceSystem>();
        transformPool = new HashMap<String, CoordinateTransform>();
    }
    
    /**
     * 获得地理坐标系（自动缓存）
     */
    public CoordinateReferenceSystem getCoordinateSystem(String csName) {
        CoordinateReferenceSystem cs = csPool.get(csName);
        if (cs != null) {
            return cs;
        }
            
        cs = GeographyUtil.getGeoCoordinateSystem(csName);
        if (cs == null) {
            return null;
        }
        csPool.put(csName, cs);
        return cs;
    }
    
    /**
     * 获得地理转换（自动缓存）
     */
    public CoordinateTransform getCoordinateTransform(String srcCS, String tgtCS) {
        
        String name = com.bgyrobot.coordinate.model.CoordinateTransform.hashString(srcCS, tgtCS, null);
        CoordinateTransform trans = transformPool.get(name);
        if (trans != null) {
            return trans;
        }
        
        if (getCoordinateSystem(srcCS) == null || getCoordinateSystem(tgtCS) == null) {
            return null;
        }
        trans = GeographyUtil.getGeotransform(srcCS, tgtCS);
        if (trans == null) {
            return null;
        }
        transformPool.put(name, trans);
        return trans;
    }
    
    /**
     * 对一个地理坐标系进行 缓存/清除缓存
     */
    public void cacheCoordinateSystem(CoordinateReferenceSystem cs, boolean isSave) {
        if (cs == null) {
            return;
        }
        String key = cs.getName();
        if (isSave) {
            csPool.put(key, cs);
            return;
        }
        if (csPool.containsKey(key)) {
            csPool.remove(key);
        }
    }
    
    /**
     * 对一个地理转换进行 缓存/清除缓存
     */
    public void cacheCoordinateTransform(CoordinateTransform transform, boolean isSave) {
        if (transform == null) {
            return;
        }
        String key = com.bgyrobot.coordinate.model.CoordinateTransform.hashString(
                transform.getSourceCRS().getName(),
                transform.getTargetCRS().getName(),
                null);
        if (isSave) {
            transformPool.put(key, transform);
            return;
        }
        if (transformPool.containsKey(key)) {
            transformPool.remove(key);
        }
    }
    
    /**
     * 对地理坐标转换 求解出其 拟合转换矩阵
     * @param srcCS 源坐标系名称
     * @param tgtCS 目标坐标系名称
     * @param refPoint 参考点
     * @return 拟合转换矩阵
     */
    public double[][] geotransformToMatrix(String srcCS, String tgtCS, ReferencePoint refPoint) {
        if (refPoint == null || !refPoint.valid()) {
            return null;
        }
        CoordinateTransform trans = getCoordinateTransform(srcCS, tgtCS);
        if (trans == null) {
            return null;
        }
        return GeographyUtil.geotransformToMatrix(trans, refPoint.getRefCS(), refPoint.getRefCoord());
    }
    
    /**
     * 执行地理转换
     */
    public double[][] execute(String srcCS, String tgtCS, double[][] srcCoords, boolean is2d){
        CoordinateTransform transform = getCoordinateTransform(srcCS, tgtCS);
        if (transform == null) {
            return null;
        }
        return GeographyUtil.transform(transform, srcCoords, is2d);
    }
}
